package com.sm;

// import gynsh.scf.basics.encrypt.sm2.SM2Utils;

import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.x509.X509V3CertificateGenerator;

import javax.security.auth.x500.X500Principal;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.Date;

public class SM2Demo {
    /**大前置公钥*/
    static String pubk = "04986ea6d5505c63173d001557d06216f07181376781f20b1805cd519770dd4196f4f8561ebb0540c91a61b3b3a40b9e645dbe448bb6db07efb1f1fdf487ac910f";
    /**大前置分配给调用方的应用密钥*/
//    static String prik = "00bbbf2cfe3704ecb5d0d120dbc7189eaac88579e5726d4fec84ac6747e47f8f38";
    static String prik = "0093e9228cae04d7d2c8fde04cc5125398acc7503936ce3f12daadcbc2469c76ae";
    //    static String   pubk = "040CD64F13359245B489D67BCD71A209F3FC5A0393CC0CB43F65A7F8F5852ECF03825D9E0C3A5C8E06B765E07F32505EB567126D5F7C420ABA7DBAA2790B0B4176";
    //    static String   prik = "008ABF7E03C6BB305E36281DF816E5FB8F1076C61097040A152D9773D43899E292";

    //密钥的椭圆加密参数形式
    static ECPrivateKeyParameters priKey = SM2Util.getPrivateKeyObject(prik);
    static ECPublicKeyParameters pubKey = SM2Util.getPublicKeyObject(pubk);

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public static void main(String[] args) throws IOException {
//        createCerFile();
//        encrypt();
//        sm2signtest();
        //getKeyFromfile();
 //       dencrypt();
        sign();
        verify();
    }

    public static void sign(){


        String src = "appId=123456";
        String sign = "30450221008ab81954f18b9b682adf1666486801cfb3f357ec64f64511fabfc59c29154edd02201556bbef89752008074581041abd11e8b80c9eea92a53e941061513d6c64ef26";
        try {
            byte[] signbt = SM2Util.sign(priKey, src.getBytes(StandardCharsets.UTF_8));
            sign = Hex.toHexString(signbt);
            System.out.println("签名结果："+sign);
        } catch (CryptoException e) {
            e.printStackTrace();
        }

    }
    public static void verify(){
       String src = "appId=123456";
        String sign = "30440220186d2d6b646aefeebf7b870b05a60810118c42c44c0021c50522f9b41c6e324c022070d566b0499567af83bf1df0b7cc49f1377f53caa35ed6d28e61620bb910208e";
       // String pubk = "042ded97f1409b17030d91f7dbf3b31c575761bbc7dcc547315fac858136f5598617320078345e333f290336d5e00b63f9e6005a785ddaa129276a13065514d55e";
        /**大前置分配给调用方的应用密钥*/
        ECPublicKeyParameters pubKey = SM2Util.getPublicKeyObject(pubk);
        boolean verify = SM2Util.verify(pubKey, src.getBytes(StandardCharsets.UTF_8), Hex.decode(sign));
        System.out.println("验签结果："+verify);

    }

    private static void dencrypt() {

        String str = "042a238653b91d7144421616ddf1f33879e98b1163a4354098a3bcf9d3b3bf3265d1a55689e2f68c721501afa39577a0d64e102b62d46cd1e0d44cb12fc4871cb7f8e281be58c7eb99cd07bfb1ba3f557e97d2109f409890d4d7592c56b54f63d16102a4c0b7a58d4095effdb3b3ac4e3f66b972e28452430ba9695e8071b314ffc9be2291da12df6bdb5ba4f9199735f7e4c349724f738ac1140e4af61bd503ec98d1ca88fbd6760e918629675a088954b369ebc46ab012f9c0fee1b168c68b75916efa67bf721866998a015f98b55219a475deff57816281b6e0705f51f2991cd1d67ce2b39f817fdc0830e54bedd52f457e7827f194f272bce62590c4c45a83fb2d584d523ecf9cf4";
//        byte[] decode1 = Base64.decode(str);
//        System.out.println(new String(decode1));
        byte[] decode = Hex.decode(str);
        System.out.println(new String(decode));
        byte[] decrypt = null;
        try {
            decrypt = SM2Util.decrypt(priKey,decode);
        } catch (InvalidCipherTextException e) {
            e.printStackTrace();
        }
        //decrypt = Base64.decode(decrypt);
        String decryptStr = new String(decrypt);
        System.out.println("解密后報文："+decryptStr);
    }


    public static void getKeyFromfile() {
        try {
            InputStream input = SM2Demo.class.getResourceAsStream("/certificate/test.pfx");
            PrivateKey pfx = SM2CertUtil.getPrivateKeyFromPFX(input, "123456");
            byte[] encoded = pfx.getEncoded();
            String s = Hex.toHexString(encoded);
            System.out.println(s);
            PublicKey publicKey = SM2CertUtil.getPublicKeyFromPFX(input, "123456");
            byte[] encoded1 = pfx.getEncoded();
            String s1 = Hex.toHexString(encoded1);
            System.out.println(s1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void createCerFile() {
        byte[] bytes = priKey.getD().toByteArray();
        String s2 = Hex.toHexString(bytes);
        System.out.println("私钥：" + s2);
        byte[] encoded = pubKey.getQ().getEncoded(false);
        System.out.println("没有压缩的公钥：" + Hex.toHexString(encoded));
        byte[] encoded1 = pubKey.getQ().getEncoded(true);
        System.out.println("压缩后的公钥：" + Hex.toHexString(encoded1));

        KeyPair keyPair = null;
        try {
            keyPair = SM2Util.generateKeyPair();
            PublicKey aPublicKey = keyPair.getPublic();
            PrivateKey aPrivateKey = keyPair.getPrivate();

            ECPrivateKeyParameters privateKeyParameters = BCECUtil.convertPrivateKeyToParameters((BCECPrivateKey) aPrivateKey);
            byte[] bytes1 = privateKeyParameters.getD().toByteArray();
            System.out.println("生成私钥：" + Hex.toHexString(bytes1));

            ECPublicKeyParameters ecPublicKeyParameters = BCECUtil.convertPublicKeyToParameters((BCECPublicKey) aPublicKey);
            byte[] encoded2 = ecPublicKeyParameters.getQ().getEncoded(false);
            System.out.println("生成公钥：" + Hex.toHexString(encoded2));


            System.out.println("证书原始公钥：" + Hex.toHexString(aPublicKey.getEncoded()));
            System.out.println("证书原始私钥：" + Hex.toHexString(aPrivateKey.getEncoded()));


//            CertificateFactory certFact = CertificateFactory.getInstance("X.509", new BouncyCastleProvider());
//            certFact.
//            X509Certificate x509 = new X509CertificateObject();
//            PKCS12PfxPdu pkcs12PfxPdu = sm.makePfx(priKey, pubKey, x509, "123456");


            X500Principal principal = new X500Principal("cn=中国");
            X500Principal principal2 = new X500Principal("O=贵阳农商银行");
            X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
//        X500Name issuer = new X500Name("cn=中国");
//        BigInteger serial = new BigInteger(String.valueOf(123456));
//        Date notBefore = DateLocalUtils.getSysDate();
//        Date notAfter = DateLocalUtils.getSysDate();
//        X500Name subject = new X500Name("O=贵阳农商银行");
//        ASN1Sequence aaa = new DERSequence();
//        SubjectPublicKeyInfo publicKeyInfo = new SubjectPublicKeyInfo(aaa);
//        X509v3CertificateBuilder x509v3CertificateBuilder = new X509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, publicKeyInfo);
//            x509v3CertificateBuilder.bui
            certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
            certGen.setIssuerDN(principal);
            certGen.setNotBefore(DateLocalUtils.getSysDate());
            Date date = DateLocalUtils.getSysDate();
            date.setYear(125);
            certGen.setNotAfter(date);
            certGen.setSubjectDN(principal2);
            certGen.setSignatureAlgorithm("1.2.156.10197.1.501");
            certGen.setPublicKey(aPublicKey);

            X509Certificate rootCert = certGen.generate(aPrivateKey);
            //X509Certificate rootCert = certGen.generateX509Certificate(aPrivateKey, "BC");

            FileOutputStream outputStream = new FileOutputStream("F:\\tmp\\test.cer");
            outputStream.write(rootCert.getEncoded());
            outputStream.close();
            System.out.println("生成 cer success");

            SM2PfxMaker sm = new SM2PfxMaker();
            PKCS12PfxPdu pfx = sm.makePfx(aPrivateKey, aPublicKey, rootCert, "123456");
            System.out.println(Hex.toHexString(pfx.getEncoded()));

            outputStream = new FileOutputStream("F:\\tmp\\test.pfx");
            outputStream.write(pfx.getEncoded());
            outputStream.close();
            System.out.println("生成 pfx success");

//            SM2JksMaker jksMaker = new SM2JksMaker();
//            outputStream = new FileOutputStream("F:\\tmp\\test.jks");

//            X509Certificate[] x509Certificates = new X509Certificate[1];
//            x509Certificates[0] = rootCert;
//            jksMaker.makeJks("jwt",aPrivateKey,aPublicKey,x509Certificates,"123456",outputStream);
//            outputStream.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void encrypt() {
        String data = "贵阳农商银行";
        //String s = Hex.toHexString(sign);
        byte[] strData = data.getBytes(StandardCharsets.UTF_8);
        byte[] encrypt = new byte[0];
        try {
            encrypt = SM2Util.encrypt(pubKey, strData);
        } catch (InvalidCipherTextException e) {
            e.printStackTrace();
        }
        String s = Hex.toHexString(encrypt);
        System.out.println("加密后：" + s);
        byte[] decrypt = new byte[0];
        try {
            decrypt = SM2Util.decrypt(priKey, encrypt);
        } catch (InvalidCipherTextException e) {
            e.printStackTrace();
        }
        System.out.println("解密后：" + (new String(decrypt)));

    }

    public static void sm2signtest() {
        String data = "贵阳农商银行";
        ECPrivateKeyParameters key = null;
        byte[] strData = data.getBytes(StandardCharsets.UTF_8);
        try {
            byte[] sign = SM2Util.sign(priKey, strData);
            String s = Hex.toHexString(sign);
            System.out.println("签名：" + s);
            boolean verify = SM2Util.verify(pubKey, strData, sign);
            System.out.println("验签结果：" + verify);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}